<html>
<head><meta charset="utf-8"><title>stabilize control flow · t-compiler/const-eval · Zulip Chat Archive</title></head>
<h2>Stream: <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/index.html">t-compiler/const-eval</a></h2>
<h3>Topic: <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html">stabilize control flow</a></h3>

<hr>

<base href="https://rust-lang.zulipchat.com">

<head><link href="https://rust-lang.github.io/zulip_archive/style.css" rel="stylesheet"></head>

<a name="190596894"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/190596894" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#190596894">(Mar 14 2020 at 13:08)</a>:</h4>
<p>Does anything speak against stabilizing panicking, if, match, loop and short circuiting ops? It's been on nightly for a few months, we're using it for libstd stuff already. cc <span class="user-group-mention" data-user-group-id="1916">@WG-const-eval</span></p>



<a name="190611723"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/190611723" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Dylan MacKenzie (ecstatic-morse) <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#190611723">(Mar 14 2020 at 19:58)</a>:</h4>
<p>How comfortable everyone is committing to value-based dataflow analysis, which determines whether e.g. a particular value of <code>Option&lt;Box&lt;T&gt;&gt;</code> has a meaningful destructor, as the engine that powers const-checking? You can imagine a world in which, before <code>let</code> bindings were stabilized in a const context, we only did the value-based analysis for single expressions (e.g., <code>const NULL: Option&lt;Box&lt;T&gt;&gt; = None;</code>). My concern is that we are committing to an implementation that has some compile-time overhead and will be difficult to explain to users (especially once <code>&amp;mut</code> is legal in a const context) without a lot of motivating use cases: the value based analysis allows users to write code such as the following:</p>
<div class="codehilite"><pre><span></span><span class="k">const</span><span class="w"> </span><span class="n">_</span>: <span class="p">()</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">x</span>: <span class="nb">Option</span><span class="o">&lt;</span><span class="nb">Box</span><span class="o">&lt;</span><span class="kt">i32</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">cond</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nb">None</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nb">None</span><span class="w"></span>
<span class="w">    </span><span class="p">};</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>



<a name="190611809"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/190611809" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Dylan MacKenzie (ecstatic-morse) <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#190611809">(Mar 14 2020 at 20:00)</a>:</h4>
<p>Is code in that style worth the additional runtime complexity? Or should we just use type-based analysis once a local is assigned multiple times.</p>



<a name="190611810"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/190611810" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> bjorn3 <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#190611810">(Mar 14 2020 at 20:00)</a>:</h4>
<p>Did you mean to write <code>None</code> twice?</p>



<a name="190611815"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/190611815" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Dylan MacKenzie (ecstatic-morse) <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#190611815">(Mar 14 2020 at 20:01)</a>:</h4>
<p><span class="user-mention" data-user-id="133247">@bjorn3</span> yes</p>



<a name="190611879"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/190611879" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Dylan MacKenzie (ecstatic-morse) <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#190611879">(Mar 14 2020 at 20:02)</a>:</h4>
<p>I can't think of a motivating use case at the moment, but basically the value-based dataflow analysis allows the user to assign to a local multiple times as long as the final assignment on all code paths does not have a meaningful <code>Drop</code> impl.</p>



<a name="190613045"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/190613045" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#190613045">(Mar 14 2020 at 20:30)</a>:</h4>
<p>While I'm fine with the type based analysis, won't it be confusing for users if some things only work in the trailing expression of a const initializer? We can't regress anything there so we need to keep it around anyway.</p>



<a name="190613079"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/190613079" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#190613079">(Mar 14 2020 at 20:31)</a>:</h4>
<p>That said, we can always start with a type based version and keep the value based one behind a feature gate</p>



<a name="190613081"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/190613081" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#190613081">(Mar 14 2020 at 20:31)</a>:</h4>
<p>It's strictly forward compatible</p>



<a name="190613529"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/190613529" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Dylan MacKenzie (ecstatic-morse) <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#190613529">(Mar 14 2020 at 20:43)</a>:</h4>
<p>We allow the code like the following today, so I'm not really sure what a reduced version of the value-based analysis would look like. The  "assigned once" rule isn't backwards compatible.</p>
<div class="codehilite"><pre><span></span><span class="k">const</span><span class="w"> </span><span class="n">_</span>: <span class="p">()</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">x</span>: <span class="nb">Option</span><span class="o">&lt;</span><span class="nb">Box</span><span class="o">&lt;</span><span class="kt">i32</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">None</span><span class="p">;</span><span class="w"></span>
<span class="w">    </span><span class="n">x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">None</span><span class="p">;</span><span class="w"></span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">x</span><span class="p">;</span><span class="w"></span>
<span class="w">    </span><span class="n">y</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">None</span><span class="p">;</span><span class="w"></span>
<span class="p">};</span><span class="w"></span>
</pre></div>



<a name="190613603"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/190613603" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Dylan MacKenzie (ecstatic-morse) <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#190613603">(Mar 14 2020 at 20:45)</a>:</h4>
<p>Performance hasn't been an issue so far, but in a world in which the majority of functions are <code>const fn</code> that may no longer be true.</p>



<a name="190613773"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/190613773" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Dylan MacKenzie (ecstatic-morse) <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#190613773">(Mar 14 2020 at 20:49)</a>:</h4>
<p><span class="user-mention silent" data-user-id="118594">ecstatic-morse</span> <a href="#narrow/stream/146212-t-compiler.2Fconst-eval/topic/stabilize.20control.20flow/near/190613529" title="#narrow/stream/146212-t-compiler.2Fconst-eval/topic/stabilize.20control.20flow/near/190613529">said</a>:</p>
<blockquote>
<p>We allow the code like the following today, so I'm not really sure what a reduced version of the value-based analysis would look like. The  "assigned once" rule isn't backwards compatible.</p>
</blockquote>
<p>So maybe we have no realistic option besides the status quo, but it's probably good to explore the solution space a bit.</p>



<a name="190613814"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/190613814" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Dylan MacKenzie (ecstatic-morse) <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#190613814">(Mar 14 2020 at 20:50)</a>:</h4>
<p>before stabilizing</p>



<a name="190957407"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/190957407" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#190957407">(Mar 18 2020 at 09:48)</a>:</h4>
<p><span class="user-mention silent" data-user-id="118594">ecstatic-morse</span> <a href="#narrow/stream/146212-t-compiler.2Fconst-eval/topic/stabilize.20control.20flow/near/190613603" title="#narrow/stream/146212-t-compiler.2Fconst-eval/topic/stabilize.20control.20flow/near/190613603">said</a>:</p>
<blockquote>
<p>Performance hasn't been an issue so far, but in a world in which the majority of functions are <code>const fn</code> that may no longer be true.</p>
</blockquote>
<p>We could benchmark this. We can run the const fn analysis without emitting errors on all functions</p>



<a name="191491472"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/191491472" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> eddyb <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#191491472">(Mar 23 2020 at 15:38)</a>:</h4>
<p><span class="user-mention" data-user-id="118594">@ecstatic-morse</span> a more realistic example would choose between multiple variants, none of which need drop or w/e</p>



<a name="191963383"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/191963383" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Dylan MacKenzie (ecstatic-morse) <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#191963383">(Mar 26 2020 at 23:52)</a>:</h4>
<p><span class="user-mention silent" data-user-id="124288">oli</span> <a href="#narrow/stream/146212-t-compiler.2Fconst-eval/topic/stabilize.20control.20flow/near/190957407" title="#narrow/stream/146212-t-compiler.2Fconst-eval/topic/stabilize.20control.20flow/near/190957407">said</a>:</p>
<blockquote>
<p>We could benchmark this. We can run the const fn analysis without emitting errors on all functions</p>
</blockquote>
<p>see <a href="https://github.com/rust-lang/rust/issues/70450" title="https://github.com/rust-lang/rust/issues/70450">#70450</a></p>



<a name="193536822"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/193536822" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Dylan MacKenzie (ecstatic-morse) <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#193536822">(Apr 10 2020 at 04:14)</a>:</h4>
<p><span class="user-mention" data-user-id="124288">@oli</span> <a href="https://perf.rust-lang.org/compare.html?start=93dc97a85381cc52eb872d27e50e4d518926a27c&amp;end=51cf313c7946365d5be38113950703c6aea9f2f3" title="https://perf.rust-lang.org/compare.html?start=93dc97a85381cc52eb872d27e50e4d518926a27c&amp;end=51cf313c7946365d5be38113950703c6aea9f2f3">https://perf.rust-lang.org/compare.html?start=93dc97a85381cc52eb872d27e50e4d518926a27c&amp;end=51cf313c7946365d5be38113950703c6aea9f2f3</a></p>



<a name="193536844"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/193536844" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Dylan MacKenzie (ecstatic-morse) <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#193536844">(Apr 10 2020 at 04:14)</a>:</h4>
<p>This runs the dataflow analyses required for const-checking on every function that doesn't return an opaque type, which caused query cycles.</p>



<a name="193537004"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/193537004" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Dylan MacKenzie (ecstatic-morse) <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#193537004">(Apr 10 2020 at 04:19)</a>:</h4>
<p>up to 5% slower on check builds</p>



<a name="193537026"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/193537026" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Dylan MacKenzie (ecstatic-morse) <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#193537026">(Apr 10 2020 at 04:19)</a>:</h4>
<p>which may be acceptable?</p>



<a name="193537080"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/193537080" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Dylan MacKenzie (ecstatic-morse) <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#193537080">(Apr 10 2020 at 04:20)</a>:</h4>
<p>Also, <code>wg-grammar</code> had a different cycle error, so there's no results for it</p>



<a name="193642691"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/193642691" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> centril <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#193642691">(Apr 11 2020 at 04:57)</a>:</h4>
<p>3% average, remembering that this is worst case that won't happen in many many years, feels very acceptable</p>



<a name="193682524"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/193682524" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> centril <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#193682524">(Apr 11 2020 at 22:19)</a>:</h4>
<p><span class="user-mention silent" data-user-id="124288">oli</span> <a href="#narrow/stream/146212-t-compiler.2Fconst-eval/topic/stabilize.20control.20flow/near/190613079" title="#narrow/stream/146212-t-compiler.2Fconst-eval/topic/stabilize.20control.20flow/near/190613079">said</a>:</p>
<blockquote>
<p>That said, we can always start with a type based version and keep the value based one behind a feature gate</p>
</blockquote>
<p>I would prefer doing this. I think it's better to roll out a more conservative version first, then see how it's used and extend if necessary. It would also be easier from the POV of specification and testing, and I would have an easier time to sign-off as it would be something I could understand, unlike the dataflow version (though I need to immerse myself in that).</p>



<a name="193894590"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/193894590" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#193894590">(Apr 14 2020 at 13:16)</a>:</h4>
<p>No promises that the type based version will not also have a similar slowdown ;)</p>



<a name="193934505"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/193934505" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> centril <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#193934505">(Apr 14 2020 at 17:55)</a>:</h4>
<p>I'm not too concerned about that aspect <span aria-label="slight smile" class="emoji emoji-1f642" role="img" title="slight smile">:slight_smile:</span></p>



<a name="193944644"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/193944644" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Dylan MacKenzie (ecstatic-morse) <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#193944644">(Apr 14 2020 at 19:16)</a>:</h4>
<p>So the conservative version is basically: Look for a <code>SwitchInt</code> terminator in the body. If one exists, fall back to type-based qualification (we only need to consider <code>SwitchInt</code> since we don't const-check the unwind path). Otherwise use the existing dataflow-based qualification since it's equivalent to a linear approach. There's probably some edge-cases around e.g. exhaustive single-arm match statements.</p>
<p>This will be difficult to explain to users if they are relying on value-based const qualification. For example, adding an unrelated <code>assert</code> to <code>foo</code> will cause it to no longer compile  (taking a reference is only legal if  we can prove<code>T: Freeze</code>).</p>
<div class="codehilite"><pre><span></span><span class="k">const</span><span class="w"> </span><span class="k">fn</span> <span class="nf">foo</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="kp">&amp;</span><span class="nb">&#39;static</span><span class="w"> </span><span class="nb">Option</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="o">&amp;</span><span class="nb">None</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>


<p>I'd like to talk about this at a lang team meeting. It's worth noting that we could put off running dataflow until we actually see a <code>Drop</code> terminator or <code>Rvalue::Ref</code> for a type that <em>may</em> have <code>NeedsDrop</code> or <code>Rvalue::Ref</code>, so the worst-case is probably less than 2-5%.</p>



<a name="193945059"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/193945059" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Dylan MacKenzie (ecstatic-morse) <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#193945059">(Apr 14 2020 at 19:20)</a>:</h4>
<p>OTOH, I'm guessing that many real-world uses of branchy <code>const fn</code> are  using primitive integer types, which will work just fine with the conservative approach. Of course, these are the same examples that would benefit from lazily doing dataflow.</p>



<a name="194019256"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/194019256" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#194019256">(Apr 15 2020 at 12:10)</a>:</h4>
<p><span class="user-mention" data-user-id="118594">@ecstatic-morse</span> that const fn doesn't compile without such an assert either</p>



<a name="194019505"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/194019505" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#194019505">(Apr 15 2020 at 12:12)</a>:</h4>
<p>I believe a better example is</p>
<div class="codehilite"><pre><span></span><span class="k">const</span><span class="w"> </span><span class="k">fn</span> <span class="nf">foo</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Option</span>::<span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span>::<span class="nb">None</span><span class="p">;</span><span class="w"></span>
<span class="w">    </span><span class="p">{</span><span class="n">x</span><span class="p">};</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>



<a name="194022699"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/194022699" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#194022699">(Apr 15 2020 at 12:38)</a>:</h4>
<p>I wrote up <a href="https://github.com/rust-lang/rust/issues/49146#issuecomment-614012476" title="https://github.com/rust-lang/rust/issues/49146#issuecomment-614012476">https://github.com/rust-lang/rust/issues/49146#issuecomment-614012476</a> and nominated it for T-lang discussion</p>



<a name="194022735"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/194022735" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#194022735">(Apr 15 2020 at 12:38)</a>:</h4>
<p>imo we should just go with the full version to keep the implementation and language simple</p>



<a name="194022747"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/194022747" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#194022747">(Apr 15 2020 at 12:38)</a>:</h4>
<p>special cases just breed problems</p>



<a name="194393440"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/194393440" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Dylan MacKenzie (ecstatic-morse) <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#194393440">(Apr 17 2020 at 03:47)</a>:</h4>
<p>This was discussed during the lang team meeting today. I'm going to write up a stabilization report and propose we start FCP. I'll post a draft here before I put in on GitHub.</p>
<p>One of the things niko asked for was a recommendation from const-eval people. I know that <span class="user-mention" data-user-id="124288">@oli</span> and I are both in favor of stabilizing the current behavior, which I'll note in the proposal. <span class="user-mention" data-user-id="120791">@RalfJ</span>  lemme know if you have thoughts that you want included in the stabilization report.</p>



<a name="194398883"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/194398883" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#194398883">(Apr 17 2020 at 06:24)</a>:</h4>
<p>Hm, I mostly stayed out of const-checking discussion and I am not familiar with the new const-checking framework (just very happy to see the old mess gone).</p>



<a name="194398910"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/194398910" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#194398910">(Apr 17 2020 at 06:25)</a>:</h4>
<p>My focus for const-eval is the Miri engine itself, and I am fairly confident that that correctly implements all Rust control flow operators and that at least post-monomorphization, we also catch all const-correctness concerns (modulo what is tracked in <a href="https://github.com/rust-lang/const-eval/issues/17" title="https://github.com/rust-lang/const-eval/issues/17">https://github.com/rust-lang/const-eval/issues/17</a>).</p>



<a name="194398993"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/194398993" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#194398993">(Apr 17 2020 at 06:26)</a>:</h4>
<p>Since stabilization concerns seem to be mostly about the static const-checking, I'm afraid I don't think I have much to contribute, and I probably won't have the time to dig into that code to give an informed opinion. I trust you guys on that. :)</p>



<a name="194499695"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/194499695" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Dylan MacKenzie (ecstatic-morse) <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#194499695">(Apr 17 2020 at 21:04)</a>:</h4>
<h1>Summary</h1>
<p>I propose that we stabilize <code>#![feature(const_if_match)]</code> with the current<br>
semantics.</p>
<p>Specifically, <code>if</code> and <code>match</code> expressions as well as the short-circuiting<br>
logic operators <code>&amp;&amp;</code> and <code>||</code> will become legal in all const contexts. A const<br>
context is any of the following:</p>
<ul>
<li>The initializer of a <code>const</code>, <code>static</code>, <code>static mut</code> or enum discriminant.</li>
<li>The body of a <code>const fn</code>.</li>
<li>The value of a const generic.</li>
<li>The length of an array type (<code>[u8; 3]</code>) or an array repeat expression (<code>[0u8; 3]</code>).</li>
</ul>
<p>Furthermore, the short-circuiting logic operators will no longer be lowered to<br>
their bitwise equivalents (<code>&amp;</code> and <code>|</code> respectively) in <code>const</code> and <code>static</code><br>
initializers (see <a href="https://github.com/rust-lang/rust/issues/57175" title="https://github.com/rust-lang/rust/issues/57175">#57175</a>). As a result, <code>let</code> bindings can be used alongside<br>
short-circuiting logic in those initializers.</p>
<p>Tracking issue: <a href="https://github.com/rust-lang/rust/issues/49146" title="https://github.com/rust-lang/rust/issues/49146">#49146</a><br>
Version target: 1.45 (2020-06-16)</p>
<h2>Implementation History</h2>
<p><a href="https://github.com/rust-lang/rust/issues/64470" title="https://github.com/rust-lang/rust/issues/64470">#64470</a> implemented a value-based static analysis that supported conditional<br>
control-flow and was based on dataflow. This, along with <a href="https://github.com/rust-lang/rust/issues/63812" title="https://github.com/rust-lang/rust/issues/63812">#63812</a>, allowed us<br>
to replace the old const-checking code with one that worked on complex<br>
control-flow graphs. The old const-checker was run in parallel with the<br>
dataflow-based one for a time to make sure that they agreed on programs with<br>
simple control flow. <a href="https://github.com/rust-lang/rust/issues/66385" title="https://github.com/rust-lang/rust/issues/66385">#66385</a> removed the old const-checker in favor of the<br>
dataflow-based one.</p>
<p><a href="https://github.com/rust-lang/rust/issues/66507" title="https://github.com/rust-lang/rust/issues/66507">#66507</a> implemented the <code>#![feature(const_if_match)]</code> feature gate with the<br>
semantics that are now being proposed for stabilization.</p>
<h2>Const Qualification</h2>
<h3>Background</h3>
<p>[Miri] has powered compile-time function evaluation (CTFE) in <code>rustc</code> for<br>
several years now, and has been able to evaluate conditional statements for at<br>
least that long. During CTFE, we must avoid certain operations, such<br>
as calling custom <code>Drop</code> impls or taking a reference to a value with interior<br>
mutability. Collectively, these disqualifying properties are known as<br>
"qualifications", and the process of determining whether a value has a<br>
qualification at a specific point in the program is known as "const<br>
qualification".</p>
<p>Miri is perfectly capable of emitting an error when it encounters an illegal<br>
operation on a qualified value, and it can do so with no false positives.<br>
However, CTFE occurs post-monomorphization, meaning it cannot know if constants<br>
defined in a generic context are valid until they are instantiated by a<br>
downstream crate. To get pre-monomorphization errors, we must implement a<br>
static analysis that does const qualification. In general, const qualification<br>
is undecidable (it is isomorphic to the halting problem), so any static<br>
analysis can only approximate the checks that Miri performs during CTFE.</p>
<p>Our static analysis must forbid a reference to a type with interior mutability<br>
(e.g. <code>&amp;Cell&lt;i32&gt;</code>) from appearing in the final value of a <code>const</code>.  If this<br>
were allowed, a <code>const</code> could be modified at run-time.</p>
<div class="codehilite"><pre><span></span><span class="c1">// ILLEGAL: A reference to a type with interior mutability cannot appear in the final value of a `const`.</span>
<span class="k">const</span><span class="w"> </span><span class="n">X</span>: <span class="kp">&amp;</span><span class="nc">std</span>::<span class="n">cell</span>::<span class="n">Cell</span><span class="o">&lt;</span><span class="kt">i32</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&amp;</span><span class="n">std</span>::<span class="n">cell</span>::<span class="n">Cell</span>::<span class="n">new</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span><span class="w"></span>

<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">  </span><span class="n">X</span><span class="p">.</span><span class="n">get</span><span class="p">();</span><span class="w"> </span><span class="c1">// 0</span>
<span class="w">  </span><span class="n">X</span><span class="p">.</span><span class="n">set</span><span class="p">(</span><span class="mi">42</span><span class="p">);</span><span class="w"></span>
<span class="w">  </span><span class="n">X</span><span class="p">.</span><span class="n">get</span><span class="p">();</span><span class="w"> </span><span class="c1">// 42</span>
<span class="p">}</span><span class="w"></span>
</pre></div>


<p>However, we allow the user to define a <code>const</code> whose <em>type</em> has interior<br>
mutability (<code>!Freeze</code>) as long as we can prove that the final <em>value</em> of that<br>
<code>const</code> does not. For example, the following has compiled since [the first<br>
edition of stable rust][rustv1]:</p>
<div class="codehilite"><pre><span></span><span class="k">const</span><span class="w"> </span><span class="n">_X</span>: <span class="nb">Option</span><span class="o">&lt;&amp;</span><span class="nb">&#39;static</span><span class="w"> </span><span class="n">std</span>::<span class="n">cell</span>::<span class="n">Cell</span><span class="o">&lt;</span><span class="kt">i32</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">None</span><span class="p">;</span><span class="w"></span>
</pre></div>


<p>This approach to static analysis, which I will call value-based as opposed to<br>
type-based, is also used to check for code that may result in a custom <code>Drop</code><br>
impl being called. Calling <code>Drop</code> impls is problematic because they are not<br>
const-checked and thus can contain code that would not be allowed in a const<br>
context. Value-based reasoning was extended to support <code>let</code> statements,<br>
meaning the following [compiles on rust 1.42.0 stable][drop].</p>
<div class="codehilite"><pre><span></span><span class="k">const</span><span class="w"> </span><span class="n">_</span>: <span class="nb">Option</span><span class="o">&lt;</span><span class="nb">Vec</span><span class="o">&lt;</span><span class="kt">i32</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">  </span><span class="kd">let</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">None</span><span class="p">;</span><span class="w"></span>
<span class="w">  </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">x</span><span class="p">;</span><span class="w"></span>
<span class="w">  </span><span class="n">y</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="nb">Vec</span>::<span class="n">new</span><span class="p">());</span><span class="w"> </span><span class="c1">// Causes the old value in `y` to be dropped.</span>
<span class="w">  </span><span class="n">y</span><span class="w"></span>
<span class="p">};</span><span class="w"></span>
</pre></div>


<h3>Current Semantics</h3>
<p>The current behavior of <code>#![feature(const_if_match)]</code> extends the value-based<br>
semantics to work on complex control-flow graphs by using dataflow. In other<br>
words, we try to prove that a variable does not have the qualification in<br>
question along <em>all possible paths</em> through the program.</p>
<div class="codehilite"><pre><span></span><span class="k">enum</span> <span class="nc">Int</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="n">Zero</span><span class="p">,</span><span class="w"></span>
<span class="w">    </span><span class="n">One</span><span class="p">,</span><span class="w"></span>
<span class="w">    </span><span class="n">Many</span><span class="p">(</span><span class="nb">String</span><span class="p">),</span><span class="w"> </span><span class="c1">// Dropping this variant is not allowed in a `const fn`...</span>
<span class="p">}</span><span class="w"></span>

<span class="c1">// ...but the following code is legal under this proposal...</span>
<span class="k">const</span><span class="w"> </span><span class="k">fn</span> <span class="nf">good</span><span class="p">(</span><span class="n">x</span>: <span class="kt">i32</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="mi">0</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="n">Int</span>::<span class="n">Zero</span><span class="p">,</span><span class="w"></span>
<span class="w">        </span><span class="mi">1</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="n">Int</span>::<span class="n">One</span><span class="p">,</span><span class="w"></span>
<span class="w">        </span><span class="n">_</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="k">return</span><span class="p">,</span><span class="w"></span>
<span class="w">    </span><span class="p">};</span><span class="w"></span>

<span class="w">    </span><span class="c1">// ...because `i` is never `Int::Many` on any possible path through the program.</span>
<span class="w">    </span><span class="n">std</span>::<span class="n">mem</span>::<span class="n">drop</span><span class="p">(</span><span class="n">i</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>


<p>All possible paths through the program include ones that may never be reached<br>
in practice as long as they exist in the source code. An example, using the<br>
same <code>Int</code> enum as above:</p>
<div class="codehilite"><pre><span></span><span class="k">const</span><span class="w"> </span><span class="k">fn</span> <span class="nf">bad</span><span class="p">(</span><span class="n">b</span>: <span class="kt">bool</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="kc">true</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="n">Int</span>::<span class="n">One</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="kc">false</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="n">Int</span>::<span class="n">Zero</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="c1">// This branch is dead code. It can never be reached in practice.</span>
<span class="w">        </span><span class="c1">// However, const qualification treats it as a possible path because it</span>
<span class="w">        </span><span class="c1">// exists in the source code.</span>
<span class="w">        </span><span class="n">Int</span>::<span class="n">Many</span><span class="p">(</span><span class="nb">String</span>::<span class="n">new</span><span class="p">())</span><span class="w"></span>
<span class="w">    </span><span class="p">};</span><span class="w"></span>

<span class="w">    </span><span class="c1">// ILLEGAL: `i` was assigned the `Int::Many` variant on at least one code path.</span>
<span class="w">    </span><span class="n">std</span>::<span class="n">mem</span>::<span class="n">drop</span><span class="p">(</span><span class="n">i</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>


<p>This analysis treats function calls as opaque, assuming that their return value<br>
may contain any value of its type. We also fall back to a type-based analysis<br>
for a variable as soon as a mutable reference to it is created. Note that<br>
creating a mutable reference in a const context is currently forbidden on<br>
stable rust.</p>
<div class="codehilite"><pre><span></span><span class="cp">#![feature(const_mut_refs)]</span><span class="w"></span>

<span class="k">const</span><span class="w"> </span><span class="k">fn</span> <span class="nf">none</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="nb">Option</span><span class="o">&lt;</span><span class="n">Cell</span><span class="o">&lt;</span><span class="kt">i32</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nb">None</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="c1">// ILLEGAL: We must assume that `none` may return any value of type `Option&lt;Cell&lt;i32&gt;&gt;`.</span>
<span class="k">const</span><span class="w"> </span><span class="n">BAD</span>: <span class="kp">&amp;</span><span class="nb">Option</span><span class="o">&lt;</span><span class="n">Cell</span><span class="o">&lt;</span><span class="kt">i32</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">none</span><span class="p">();</span><span class="w"></span>

<span class="k">const</span><span class="w"> </span><span class="k">fn</span> <span class="nf">also_bad</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Option</span>::<span class="o">&lt;</span><span class="nb">Box</span><span class="o">&lt;</span><span class="kt">i32</span><span class="o">&gt;&gt;</span>::<span class="nb">None</span><span class="p">;</span><span class="w"></span>

<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">_</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&amp;</span><span class="k">mut</span><span class="w"> </span><span class="n">x</span><span class="p">;</span><span class="w"></span>

<span class="w">    </span><span class="c1">// ILLEGAL: because a mutable reference to `x` was created, we can no</span>
<span class="w">    </span><span class="c1">// longer assume anything about its value.</span>
<span class="w">    </span><span class="n">std</span>::<span class="n">mem</span>::<span class="n">drop</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>


<h2>Alternatives</h2>
<p>I've found it difficult to come up with practical, backwards compatible<br>
alternatives to the existing approach. We could fall back to type-based<br>
analysis for all variables as soon as conditionals are used in a const context.<br>
However, that would also be difficult to explain to users, since seemingly<br>
unrelated additions would cause code to no longer compile, such as the <code>assert</code><br>
in the following example from @oli-obk.</p>
<div class="codehilite"><pre><span></span><span class="k">const</span><span class="w"> </span><span class="k">fn</span> <span class="nf">foo</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="n">b</span>: <span class="kt">bool</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Option</span>::<span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span>::<span class="nb">None</span><span class="p">;</span><span class="w"></span>
<span class="w">    </span><span class="n">assert</span><span class="o">!</span><span class="p">(</span><span class="n">b</span><span class="p">);</span><span class="w"></span>
<span class="w">    </span><span class="p">{</span><span class="n">x</span><span class="p">};</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>


<p>The increased expressiveness of the dataflow-based analysis is not free. A<br>
perf run that did const qualification on all item bodies, not just <code>const</code><br>
ones, showed up to a [5% regression on check builds][perf]. This is a<br>
worst-case scenario, as it assumes that all items will be made <code>const</code> at some<br>
point in the future. It also assumes no further optimizations are done to const<br>
qualification. Some possible ones are discussed earlier in this thread.</p>
<h2>Future work</h2>
<p>At the moment, const-checking is run before drop elaboration, meaning some drop<br>
terminators remain in the MIR that are unreachable in practice. This is<br>
preventing <code>Option::unwrap</code> from becoming <code>const fn</code> (see <a href="https://github.com/rust-lang/rust/issues/66753" title="https://github.com/rust-lang/rust/issues/66753">#66753</a>). This is<br>
not too hard to resolve, but it will require splitting the const-checking pass<br>
into two phases (pre- and post-drop elaboration).</p>
<p>Once <code>#![feature(const_if_match)]</code> is stabilized, a great deal of library<br>
functions can be made <code>const fn</code>. This includes many methods on primitive<br>
integer types, which have been enumerated in <a href="https://github.com/rust-lang/rust/issues/53718" title="https://github.com/rust-lang/rust/issues/53718">#53718</a>.</p>
<p>Loops in a const context are blocked on the same const qualification question<br>
that was blocking conditionals. The dataflow-based analysis extends to cyclic<br>
CFGs as well, so if <code>#![feature(const_if_match)]</code> is stabilized, the main<br>
blocker for loops will be gone.</p>
<h2>Acknowledgements</h2>
<p>Special thanks are due to @oli-obk and @eddyb, who were the primary reviewers<br>
for most of the implementation work, as well as the rest of<br>
@rust-lang/wg-const-eval for helping me understand the relevant issues<br>
around const qualification. None of this would be possible without Miri,<br>
which was created by @solson and now maintained by @RalfJ and @oli-obk.</p>
<p>[Miri]: <a href="https://github.com/rust-lang/miri" title="https://github.com/rust-lang/miri">https://github.com/rust-lang/miri</a><br>
[rustv1]: <a href="https://rust.godbolt.org/z/Md59pg" title="https://rust.godbolt.org/z/Md59pg">https://rust.godbolt.org/z/Md59pg</a><br>
[drop]: <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2018&amp;gist=2b35bd82d1899cc69c7d46aeaed87e50" title="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2018&amp;gist=2b35bd82d1899cc69c7d46aeaed87e50">https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2018&amp;gist=2b35bd82d1899cc69c7d46aeaed87e50</a><br>
[perf]: <a href="https://perf.rust-lang.org/compare.html?start=93dc97a85381cc52eb872d27e50e4d518926a27c&amp;end=51cf313c7946365d5be38113950703c6aea9f2f3" title="https://perf.rust-lang.org/compare.html?start=93dc97a85381cc52eb872d27e50e4d518926a27c&amp;end=51cf313c7946365d5be38113950703c6aea9f2f3">https://perf.rust-lang.org/compare.html?start=93dc97a85381cc52eb872d27e50e4d518926a27c&amp;end=51cf313c7946365d5be38113950703c6aea9f2f3</a></p>



<a name="194499805"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/194499805" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Dylan MacKenzie (ecstatic-morse) <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#194499805">(Apr 17 2020 at 21:05)</a>:</h4>
<p>Phew, that's quite long, but hopefully gives enough background that I don't have to explain the history of const qualification anymore.</p>



<a name="194499933"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/194499933" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Dylan MacKenzie (ecstatic-morse) <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#194499933">(Apr 17 2020 at 21:06)</a>:</h4>
<p>Lemme know if I missed anything, particularly in the implementation work section, since I basically just included my own stuff.</p>



<a name="194509161"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/194509161" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> eddyb <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#194509161">(Apr 17 2020 at 22:47)</a>:</h4>
<p>wow that looks awesome</p>



<a name="194509513"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/194509513" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Dylan MacKenzie (ecstatic-morse) <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#194509513">(Apr 17 2020 at 22:52)</a>:</h4>
<p>I remain in awe of <a href="https://github.com/rust-lang/rust/issues/67712" title="https://github.com/rust-lang/rust/issues/67712">#67712</a>.</p>



<a name="194509574"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/194509574" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> eddyb <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#194509574">(Apr 17 2020 at 22:53)</a>:</h4>
<p>okay now that is just showing off</p>



<a name="194533583"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/194533583" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#194533583">(Apr 18 2020 at 08:41)</a>:</h4>
<p><span class="user-mention" data-user-id="118594">@ecstatic-morse</span> this is great, thanks a lot for the write-up!</p>



<a name="194533630"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/194533630" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#194533630">(Apr 18 2020 at 08:42)</a>:</h4>
<p>I think we might be able to copy some of that into the rustc-dev-guide verbatim, like the interaction of pre-mono const qualification and post-mono miri checks. Cc <a href="https://github.com/rust-lang/rustc-dev-guide/pull/676" title="https://github.com/rust-lang/rustc-dev-guide/pull/676">https://github.com/rust-lang/rustc-dev-guide/pull/676</a></p>



<a name="194533634"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/194533634" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#194533634">(Apr 18 2020 at 08:42)</a>:</h4>
<blockquote>
<p>Furthermore, the short-circuiting logic operators will no longer be lowered to<br>
their bitwise equivalents (&amp; and | respectively) in const and static<br>
initializers</p>
</blockquote>
<p>I am <em>so</em> happy to see this hack die! <span aria-label="flame" class="emoji emoji-1f525" role="img" title="flame">:flame:</span></p>



<a name="194598677"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/194598677" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Santiago Pastorino <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#194598677">(Apr 19 2020 at 13:51)</a>:</h4>
<p><span class="user-mention silent" data-user-id="120791">RalfJ</span> <a href="#narrow/stream/146212-t-compiler.2Fconst-eval/topic/stabilize.20control.20flow/near/194533630" title="#narrow/stream/146212-t-compiler.2Fconst-eval/topic/stabilize.20control.20flow/near/194533630">said</a>:</p>
<blockquote>
<p>I think we might be able to copy some of that into the rustc-dev-guide verbatim, like the interaction of pre-mono const qualification and post-mono miri checks. Cc <a href="https://github.com/rust-lang/rustc-dev-guide/pull/676" title="https://github.com/rust-lang/rustc-dev-guide/pull/676">https://github.com/rust-lang/rustc-dev-guide/pull/676</a></p>
</blockquote>
<p><span class="user-mention" data-user-id="118594">@ecstatic-morse</span> ohh yes, as <span class="user-mention" data-user-id="120791">@RalfJ</span> have said, would be great if we copy some of this stuff to the rustc-dev-guide <span aria-label="slight smile" class="emoji emoji-1f642" role="img" title="slight smile">:slight_smile:</span></p>



<a name="194615222"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/194615222" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Dylan MacKenzie (ecstatic-morse) <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#194615222">(Apr 19 2020 at 19:57)</a>:</h4>
<p>Sounds good. I'll wait until that PR is merged and come over the top with something.</p>



<a name="194615304"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/194615304" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Dylan MacKenzie (ecstatic-morse) <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#194615304">(Apr 19 2020 at 19:59)</a>:</h4>
<p>I was hoping to get <span class="user-mention" data-user-id="124288">@oli</span>'s eyes on this before uploading. I'll wait until tonight (in ~8 hours) and then post it.</p>



<a name="194804047"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/194804047" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#194804047">(Apr 21 2020 at 13:50)</a>:</h4>
<p>reading now</p>



<a name="194804601"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/194804601" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#194804601">(Apr 21 2020 at 13:54)</a>:</h4>
<p>general note: maybe some things could use links to the reference (e.g. for const contexts)</p>



<a name="194806553"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/194806553" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#194806553">(Apr 21 2020 at 14:07)</a>:</h4>
<p>We should mention that it may be desirable to stabilize loops at the same time, as otherwise users can just write "loops" via recursion, which may cause weird crates to be created just to work around the issue that we don't have loops stabilized</p>



<a name="194819469"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/194819469" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#194819469">(Apr 21 2020 at 15:30)</a>:</h4>
<p>One related thing is that we have the chance to make <a href="https://github.com/rust-lang/rust/issues/62411" title="https://github.com/rust-lang/rust/issues/62411">https://github.com/rust-lang/rust/issues/62411</a> a hard error in const fns</p>



<a name="194821248"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/194821248" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Dylan MacKenzie (ecstatic-morse) <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#194821248">(Apr 21 2020 at 15:42)</a>:</h4>
<p>I added a link to const contexts to the summary. I think the next two would be good "concern"s? Or do we wanna try to resolve those ahead of time?</p>



<a name="194821747"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/146212-t-compiler/const-eval/topic/stabilize%20control%20flow/near/194821747" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/146212-t-compiler/const-eval/topic/stabilize.20control.20flow.html#194821747">(Apr 21 2020 at 15:45)</a>:</h4>
<p>both are just concerns, we should ask what the lang team thinks first</p>



<hr><p>Last updated: Aug 07 2021 at 22:04 UTC</p>
</html>